home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / GL / flight / aifflib.c next >
C/C++ Source or Header  |  1994-08-01  |  22KB  |  1,084 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17.  
  18. /*
  19.  * aifflib.c $Revision: 1.3 $
  20.  *
  21.  *    A library for reading and writing AIFF files
  22.  *
  23.  *        Chris Schoeneman    - 1991
  24.  *        (borrowed heavily from playaiff and recordaiff)
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <errno.h>
  30. #include <math.h>
  31. #include <audio.h>
  32. #include "aifflib.h"
  33.  
  34.  
  35. /*
  36.  *  AIFF file typedef's and defines
  37.  */
  38. typedef struct
  39. {
  40.     long samprate;
  41.     long nchannels;
  42.     long sampwidth;
  43. } audio_params_t;
  44.  
  45. typedef struct
  46. {
  47.     char id[4];
  48.     long size;
  49. } chunk_header_t;
  50.  
  51. #define CHUNK_ID     4
  52. #define CHUNK_HEADER 8
  53.  
  54. typedef struct
  55. {
  56.     chunk_header_t header;
  57.     int file_position;    /* not in AIFF file */
  58.     char type[4];    /* should contain 'AIFF' for any audio IFF file */
  59. } form_chunk_t;
  60.  
  61. #define FORM_CHUNK      12    /* including the header */
  62. #define FORM_CHUNK_DATA 4
  63.  
  64. #define COMM_CHUNK      26    /* including the header */
  65. #define COMM_CHUNK_DATA 18
  66.  
  67. typedef struct
  68. {
  69.     chunk_header_t header;
  70.     int file_position;        /* not in AIFF file */
  71.     short nchannels;
  72.     unsigned long nsampframes;
  73.     short sampwidth;
  74.     long samprate;        /* not in AIFF file */
  75. } comm_chunk_t;
  76.  
  77.  
  78. #define SSND_CHUNK      16    /* including the header */
  79. #define SSND_CHUNK_DATA 8
  80.  
  81. typedef struct
  82. {
  83.     chunk_header_t header;
  84.     unsigned long offset;
  85.     unsigned long blocksize;
  86.  
  87.     long file_position;    /* not in AIFF file */
  88.     long sample_bytes;    /* not in AIFF file */
  89. } ssnd_chunk_t;
  90. /*
  91.  *  end of AIFF typedef's and defines
  92.  */
  93.  
  94. #define    MAXFILES    20
  95.  
  96. enum { FORM = 0, COMM = 1, SSND = 2};
  97.  
  98. #define    DEFAULT_CHANNELS    2
  99. #define    DEFAULT_WIDTH        16
  100. #define    DEFAULT_RATE        48000
  101.  
  102. static int        busy[MAXFILES],
  103.             ssnd_remaining[MAXFILES],
  104.             files = -1;
  105. static long        writepos[MAXFILES][3];
  106. static FILE*        aifffd[MAXFILES];
  107. static audio_params_t    audioparams[MAXFILES];
  108.  
  109. int        AIFFerrno;
  110. static char    *AIFFerrstr[]={
  111.             "",
  112.             "too many open files",
  113.             "cannot open file",
  114.             "invalid file id",
  115.             "invalid data size",
  116.             "invalid header",
  117.             "not an AIFF file",
  118.             "no FORM header",
  119.             "invalid chunk",
  120.             "write failure",
  121.             "audio parameters are fixed",
  122.             "unsupported number of channels",
  123.             "unsupported sample width",
  124.             "unsupported sample rate"};
  125.  
  126. static int    widthtobytes(int width);
  127. static double    ConvertFromIeeeExtended(char*);
  128. static void    ConvertToIeeeExtended(double, char*);
  129.  
  130. /*************************************************************************
  131.  **    routines to read and write the AIFF format chunks        **
  132.  *************************************************************************/
  133. /*
  134.  *  convert bytes in big endian order to a short
  135.  */
  136. static short    align_short(char* buf)
  137. {
  138.     int i;
  139.     union { unsigned char b[sizeof(short)]; short s; } align_short;
  140.  
  141.     for (i = 0; i < sizeof(short); i++)
  142.     align_short.b[i] = *buf++;
  143.     return align_short.s;
  144. }
  145.  
  146.  
  147. /*
  148.  *  convert bytes in big endian order to a long
  149.  */
  150. static long    align_long(char* buf)
  151. {
  152.     int i;
  153.     union { unsigned char b[sizeof(long)]; long l; } align_long;
  154.  
  155.     for (i = 0; i < sizeof(long); i++)
  156.     align_long.b[i] = *buf++;
  157.     return align_long.l;
  158. }
  159.  
  160.  
  161. /*
  162.  *  convert short to bytes in big endian order
  163.  */
  164. static void short_align(char* buf, short s)
  165. {
  166.     int i;
  167.     char *scan = (char*)&s;
  168.  
  169.     for (i = 0; i < sizeof(short); i++)
  170.     *buf++ = *scan++;
  171. }
  172.  
  173.  
  174. /*
  175.  *  convert long to bytes in big endian order
  176.  */
  177. static void long_align(char* buf, long l)
  178. {
  179.     int i;
  180.     char *scan = (char*)&l;
  181.  
  182.     for (i = 0; i < sizeof(long); i++)
  183.     *buf++ = *scan++;
  184. }
  185.  
  186.  
  187. static int skip_chunk(AIFFfile fd, chunk_header_t* chunk_header)
  188. {
  189.     fseek(aifffd[fd], chunk_header->size, SEEK_CUR);
  190. }
  191.  
  192.  
  193. static int read_chunk_header(AIFFfile fd, chunk_header_t *chunk_header)
  194. {
  195.     char buf[CHUNK_HEADER];
  196.     int i;
  197.  
  198.     if ((i = fread(buf, 1, CHUNK_HEADER, aifffd[fd])) != CHUNK_HEADER)
  199.     return i;
  200.  
  201.     for (i=0; i<4; i++)
  202.     chunk_header->id[i] = buf[i];
  203.     chunk_header->size = align_long(buf+4);
  204.  
  205.     return CHUNK_HEADER;
  206. }
  207.  
  208.  
  209. static int read_form_chunk(AIFFfile fd, chunk_header_t *chunk_header,
  210.                form_chunk_t *form_data)
  211. {
  212.     char buf[FORM_CHUNK_DATA];
  213.  
  214.     if (chunk_header->size < 0)
  215.     {
  216.     AIFFerrno = AIFF_BADDATASIZE;
  217.     return -1;
  218.     }
  219.     else if (chunk_header->size == 0)
  220.     {
  221.     AIFFerrno = AIFF_BADDATASIZE;
  222.     return -1;
  223.     }
  224.  
  225.     if (fread(buf, 1, FORM_CHUNK_DATA, aifffd[fd]) != FORM_CHUNK_DATA)
  226.     {
  227.     AIFFerrno = AIFF_BADHEADER;
  228.     return -1;
  229.     }
  230.     if (strncmp(buf, "AIFF", 4))
  231.     {
  232.     AIFFerrno = AIFF_NOTAIFF;
  233.     return -1;
  234.     }
  235.     return 0;
  236. }
  237.  
  238.  
  239. static int read_comm_chunk(AIFFfile fd, chunk_header_t *chunk_header)
  240. {
  241.     int i;
  242.     char buf[COMM_CHUNK_DATA+1];
  243.     comm_chunk_t comm_data;
  244.  
  245.     if (fread(buf, 1, COMM_CHUNK_DATA, aifffd[fd]) != COMM_CHUNK_DATA)
  246.     {
  247.     AIFFerrno = AIFF_BADCHUNK;
  248.     return -1;
  249.     }
  250.  
  251.     comm_data.nchannels = align_short(buf);
  252.     comm_data.nsampframes = align_long(buf+4);
  253.     comm_data.sampwidth = align_short(buf+6);
  254.  
  255.     /*
  256.      * the sample rate value from the common chunk is an 80-bit IEEE extended
  257.      * floating point number:
  258.      * [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
  259.      *
  260.      * turns out we can just grab bytes 2 and 3 (if bytes numbered 0 ... 9)
  261.      * and cast them as an integer: the integer value equals the sample rate
  262.      */
  263.     comm_data.samprate = (long)ConvertFromIeeeExtended(buf+8);
  264.  
  265.     audioparams[fd].samprate = comm_data.samprate;
  266.     audioparams[fd].nchannels = comm_data.nchannels;
  267.     audioparams[fd].sampwidth = comm_data.sampwidth;
  268.  
  269.     if (widthtobytes(audioparams[fd].sampwidth) == -1)
  270.     {
  271.     AIFFerrno = AIFF_BADWIDTH;
  272.     audioparams[fd].sampwidth = DEFAULT_WIDTH;
  273.     return -1;
  274.     }
  275.     return 0;
  276. }
  277.  
  278.  
  279. /*
  280.  *  AIFFread calls this if there is no more sound data in the current
  281.  *  SSND chunk.  It searches for the next block and sets the
  282.  *  ssnd_remaining entry to the length of the block
  283.  */
  284. static void read_ssnd_chunk(AIFFfile fd)
  285. {
  286.     char buf[SSND_CHUNK_DATA];
  287.     int i;
  288.     chunk_header_t chunk_header;
  289.  
  290.     /*
  291.      *  if no sound left, search for next SSND block
  292.      *
  293.      *  NOTE: all chunks have been read through and checked for
  294.      *  validity, so we assume read_chunk_header either returns
  295.      *  zero for end of file or CHUNK_HEADER for a good block
  296.      */
  297.     while (read_chunk_header(fd, &chunk_header) != 0)
  298.     {
  299.     if (!strncmp(chunk_header.id, "SSND", 4))
  300.     {
  301.         fread(buf, 1, SSND_CHUNK_DATA, aifffd[fd]);
  302.         ssnd_remaining[fd] = chunk_header.size - 2*sizeof(long);
  303.         if (ssnd_remaining[fd] != 0)
  304.         break;
  305.     }
  306.     else
  307.         skip_chunk(fd, &chunk_header);
  308.     }
  309. }
  310.  
  311.  
  312. static int write_form_chunk(AIFFfile fd)
  313. {
  314.     char buf[FORM_CHUNK];
  315.     int i;
  316.  
  317.     strncpy(buf, "FORM", 4);        /* form header id */
  318.     for (i=0; i<sizeof(long); i++)    /* form header size  - do later */
  319.     buf[i+4] = 0x00;
  320.     strncpy(buf+4+sizeof(long), "AIFF", 4);
  321.  
  322.     writepos[fd][FORM] = ftell(aifffd[fd]);
  323.  
  324.     if (fwrite(buf, 1, FORM_CHUNK, aifffd[fd]) != FORM_CHUNK)
  325.     {
  326.     AIFFerrno = AIFF_WRITEFAILURE;
  327.     return -1;
  328.     }
  329.  
  330.     return 0;
  331. }
  332.  
  333.  
  334. static int write_comm_chunk(AIFFfile fd)
  335. {
  336.     char buf[COMM_CHUNK];
  337.     int i;
  338.  
  339.     strncpy(buf, "COMM", 4);            /* chunk id */
  340.     long_align(buf+4,COMM_CHUNK_DATA);        /* chunk data size */
  341.     short_align(buf+4+sizeof(long),        /* number channels */
  342.         audioparams[fd].nchannels);
  343.     long_align(buf+4+sizeof(long)+sizeof(short),    /* nsample frames */
  344.            0L);
  345.     short_align(buf+4+2*sizeof(long)+sizeof(short),    /* sample width */
  346.         audioparams[fd].sampwidth);
  347.     ConvertToIeeeExtended((double)audioparams[fd].samprate, /* sample rate */
  348.               buf + 4 + 2*sizeof(long) + 2*sizeof(short));
  349.  
  350.     writepos[fd][COMM] = ftell(aifffd[fd]);
  351.  
  352.     if (fwrite(buf, 1, COMM_CHUNK, aifffd[fd]) != COMM_CHUNK)
  353.     {
  354.     AIFFerrno = AIFF_WRITEFAILURE;
  355.     return -1;
  356.     }
  357.  
  358.     ssnd_remaining[fd] = 0;
  359.  
  360.     return 0;
  361. }
  362.  
  363.  
  364. static int write_ssnd_chunk(AIFFfile fd)
  365. {
  366.     char buf[SSND_CHUNK];
  367.     int i;
  368.  
  369.     strncpy(buf, "SSND", 4);
  370.     for (i=0; i<3*sizeof(long); i++)  /* chunk data size */
  371.     buf[i+4] = 0x00;
  372.  
  373.     writepos[fd][SSND] = ftell(aifffd[fd]);
  374.  
  375.     if (fwrite(buf, 1, SSND_CHUNK, aifffd[fd]) != SSND_CHUNK)
  376.     {
  377.     AIFFerrno = AIFF_WRITEFAILURE;
  378.     return -1;
  379.     }
  380.  
  381.     return 0;
  382. }
  383.  
  384.  
  385. static int update_form_chunk(AIFFfile fd, long total_bytes)
  386. {
  387.     fseek(aifffd[fd], writepos[fd][FORM]+4, SEEK_SET);
  388.     total_bytes -= CHUNK_HEADER;
  389.  
  390.     if (fwrite(&total_bytes, 1, sizeof(long), aifffd[fd]) != sizeof(long))
  391.     {
  392.     AIFFerrno = AIFF_WRITEFAILURE;
  393.     return -1;
  394.     }
  395.  
  396.     return 0;
  397. }
  398.  
  399.  
  400. static int update_comm_chunk(AIFFfile fd, long sample_frames)
  401. {
  402.     fseek(aifffd[fd], writepos[fd][COMM]+CHUNK_HEADER+sizeof(short), SEEK_SET);
  403.  
  404.     if (fwrite(&sample_frames, 1, sizeof(long), aifffd[fd]) != sizeof(long))
  405.     {
  406.     AIFFerrno = AIFF_WRITEFAILURE;
  407.     return -1;
  408.     }
  409.  
  410.     return 0;
  411. }
  412.  
  413.  
  414. static int update_ssnd_chunk(AIFFfile fd, long sample_bytes)
  415. {
  416.     fseek(aifffd[fd], writepos[fd][SSND] + CHUNK_ID, SEEK_SET);
  417.     sample_bytes += SSND_CHUNK_DATA;
  418.  
  419.     if (fwrite(&sample_bytes, 1, sizeof(long), aifffd[fd]) != sizeof(long))
  420.     {
  421.     AIFFerrno = AIFF_WRITEFAILURE;
  422.     return -1;
  423.     }
  424.  
  425.     return 0;
  426. }
  427.  
  428.  
  429. static AIFFfile    myopen(const char* filename, const char* dir)
  430. {
  431.     int i;
  432.     FILE* fd;
  433.  
  434.     /*
  435.      *  find first available space in table
  436.      */
  437.  
  438.     for (i = 0; i < MAXFILES; i++)
  439.     if (!busy[i])
  440.         break;
  441.     if (i == MAXFILES)
  442.     {
  443.     AIFFerrno = AIFF_NOMEM;
  444.     return -1;
  445.     }
  446.  
  447.     /*
  448.      *  open file
  449.      */
  450.  
  451.     fd = fopen(filename, dir);
  452.     if (!fd)
  453.     {
  454.     AIFFerrno = AIFF_OPENFAILURE;
  455.     return -1;
  456.     }
  457.  
  458.     /*
  459.      *  fill table entries
  460.      */
  461.  
  462.     aifffd[i] = fd;
  463.     busy[i] = *dir;
  464.     files++;
  465.  
  466.     return (AIFFfile)i;
  467. }
  468.  
  469.  
  470. static int myclose(AIFFfile fd)
  471. {
  472.     busy[fd] = 0;
  473.     files--;
  474.     return fclose(aifffd[fd]);
  475. }
  476.  
  477.  
  478. AIFFfile    AIFFopen(const char* filename, const char* dir)
  479. {
  480.     AIFFfile fd;
  481.     int n;
  482.     chunk_header_t chunk_header;
  483.     form_chunk_t form_data;
  484.  
  485.     fd = myopen(filename, dir);
  486.     if (fd < 0)
  487.     return fd;
  488.  
  489.     switch (dir[0])
  490.     {
  491.     case 'r':
  492.     {
  493.         chunk_header_t chunk_header;
  494.         form_chunk_t form_data;
  495.         long past_header;
  496.  
  497.         if (read_chunk_header(fd, &chunk_header) != CHUNK_HEADER)
  498.         {
  499.         myclose(fd);
  500.         AIFFerrno = AIFF_BADHEADER;
  501.         return -1;
  502.         }
  503.  
  504.         if (strncmp(chunk_header.id, "FORM", 4))    /* form container */
  505.         {
  506.         AIFFerrno = AIFF_NOFORMCHUNK;
  507.         myclose(fd);
  508.         return -1;
  509.         }
  510.  
  511.         if (read_form_chunk(fd, &chunk_header, &form_data) < 0)
  512.         {
  513.         myclose(fd);
  514.         return -1;
  515.         }
  516.  
  517.         /*
  518.          *  remember where interesting stuff starts
  519.          */
  520.         past_header = ftell(aifffd[fd]);
  521.  
  522.         /*
  523.          *  search for last COMM chunk
  524.          */
  525.         while ((n = read_chunk_header(fd, &chunk_header)) != 0)
  526.         {
  527.         if (n == CHUNK_HEADER)
  528.         {
  529.             if (!strncmp(chunk_header.id, "COMM", 4))
  530.             read_comm_chunk(fd, &chunk_header);
  531.             else
  532.             skip_chunk(fd, &chunk_header);
  533.         }
  534.         else
  535.         {
  536.             myclose(fd);
  537.             AIFFerrno = AIFF_BADHEADER;
  538.             return -1;
  539.         }
  540.         }
  541.  
  542.         /*
  543.          *  set file pointer to beginning of interesting stuff
  544.          */
  545.         fseek(aifffd[fd], past_header, SEEK_SET);
  546.         ssnd_remaining[fd] = 0;
  547.         break;
  548.     }
  549.     case 'w':
  550.     {
  551.         /*
  552.          *  write the form chunk
  553.          */
  554.         if (write_form_chunk(fd) < 0)
  555.         {
  556.         myclose(fd);
  557.         return -1;
  558.         }
  559.  
  560.         /*
  561.          *  set ssnd_remaining to a bogus value as a flag to write the COMM
  562.          */
  563.         ssnd_remaining[fd] = -1;
  564.  
  565.         /*
  566.          *  set default values for audio parameters
  567.          */
  568.         AIFFsetchannels(fd,0);
  569.         AIFFsetwidth(fd,0);
  570.         AIFFsetrate(fd,0);
  571.  
  572.         break;
  573.     }
  574.     }
  575.  
  576.     return fd;
  577. }
  578.  
  579.  
  580. int AIFFclose(AIFFfile fd)
  581. {
  582.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  583.     {
  584.     AIFFerrno = AIFF_BADFD;
  585.     return -1;
  586.     }
  587.  
  588.     if (busy[fd] == 'w')
  589.     {
  590.     long total = ftell(aifffd[fd]);
  591.  
  592.     if (update_form_chunk(fd, total) < 0)
  593.     {
  594.         myclose(fd);
  595.         return -1;
  596.     }
  597.  
  598.     total -= FORM_CHUNK + COMM_CHUNK + SSND_CHUNK;
  599.     if (update_comm_chunk(fd, total / AIFFgetchannels(fd) /
  600.                   widthtobytes(AIFFgetwidth(fd))) < 0)
  601.     {
  602.         myclose(fd);
  603.         return -1;
  604.     }
  605.  
  606.     if (update_ssnd_chunk(fd, total) < 0)
  607.     {
  608.         myclose(fd);
  609.         return -1;
  610.     }
  611.     }
  612.  
  613.     return myclose(fd);
  614. }
  615.  
  616.  
  617. int AIFFwrite(AIFFfile fd, const void* buf, unsigned nsamp)
  618. {
  619.     int bytes_written;
  620.     unsigned nbyte;
  621.  
  622.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  623.     {
  624.     AIFFerrno = AIFF_BADFD;
  625.     return -1;
  626.     }
  627.  
  628.     /*
  629.      *  write COMM and SSND block headers if necessary
  630.      */
  631.  
  632.     if (ssnd_remaining[fd] == -1)
  633.     {
  634.     if (write_comm_chunk(fd) < 0)
  635.     {
  636.         AIFFerrno = AIFF_WRITEFAILURE;
  637.         return -1;
  638.     }
  639.     if (write_ssnd_chunk(fd) < 0)
  640.     {
  641.         AIFFerrno = AIFF_WRITEFAILURE;
  642.         return -1;
  643.     }
  644.     }
  645.  
  646.     /*
  647.      *  convert number of samples to number of bytes
  648.      */
  649.     nbyte = nsamp * widthtobytes(audioparams[fd].sampwidth);
  650.  
  651.     bytes_written = fwrite(buf, 1, nbyte, aifffd[fd]);
  652.  
  653.     /*
  654.      *  convert bytes to samples
  655.      */
  656.     return bytes_written / widthtobytes(audioparams[fd].sampwidth);
  657. }
  658.  
  659.  
  660. int AIFFread(AIFFfile fd, void* buf, unsigned nsamp)
  661. {
  662.     int bytes_read, nbyte;
  663.  
  664.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  665.     {
  666.     AIFFerrno = AIFF_BADFD;
  667.     return -1;
  668.     }
  669.  
  670.     /*
  671.      *  skip to next SSND block if necessary
  672.      */
  673.  
  674.     if (ssnd_remaining[fd] == 0)
  675.     read_ssnd_chunk(fd);
  676.  
  677.     /*
  678.      *  convert number samples to number bytes
  679.      */
  680.     nbyte = nsamp * widthtobytes(audioparams[fd].sampwidth);
  681.  
  682.     /*
  683.      *  get samples
  684.      */
  685.     /*
  686.      *  FIXME:  AIFFread should always attempt to fill the buffer
  687.      *        even if has to read the next SSND block to
  688.      *        do it (and the one after that, etc.)
  689.      */
  690.     if (ssnd_remaining[fd] < nbyte)
  691.     bytes_read = fread(buf, 1, ssnd_remaining[fd], aifffd[fd]);
  692.     else
  693.     bytes_read = fread(buf, 1, nbyte, aifffd[fd]);
  694.     ssnd_remaining[fd] -= bytes_read;
  695.  
  696.     /*
  697.      *  convert bytes to samples
  698.      */
  699.     return bytes_read / widthtobytes(audioparams[fd].sampwidth);
  700. }
  701.  
  702.  
  703. int AIFFgetlength(AIFFfile fd)
  704. {
  705.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  706.     {
  707.     AIFFerrno = AIFF_BADFD;
  708.     return -1;
  709.     }
  710.  
  711.     /*
  712.      *  skip to next SSND block if necessary
  713.      */
  714.     if (ssnd_remaining[fd] == 0)
  715.     read_ssnd_chunk(fd);
  716.  
  717.     return ssnd_remaining[fd] / widthtobytes(audioparams[fd].sampwidth);
  718. }
  719.  
  720.  
  721. int AIFFgetchannels(AIFFfile fd)
  722. {
  723.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  724.     {
  725.     AIFFerrno = AIFF_BADFD;
  726.     return -1;
  727.     }
  728.  
  729.     return audioparams[fd].nchannels;
  730. }
  731.  
  732.  
  733. int AIFFgetwidth(AIFFfile fd)
  734. {
  735.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  736.     {
  737.     AIFFerrno = AIFF_BADFD;
  738.     return -1;
  739.     }
  740.  
  741.     return audioparams[fd].sampwidth;
  742. }
  743.  
  744.  
  745. int AIFFgetrate(AIFFfile fd)
  746. {
  747.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  748.     {
  749.     AIFFerrno = AIFF_BADFD;
  750.     return -1;
  751.     }
  752.  
  753.     return audioparams[fd].samprate;
  754. }
  755.  
  756.  
  757. int AIFFsetchannels(AIFFfile fd, int channels)
  758. {
  759.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  760.     {
  761.     AIFFerrno = AIFF_BADFD;
  762.     return -1;
  763.     }
  764.  
  765.     /*
  766.      *  make sure file is write and we haven't written any sound yet
  767.      */
  768.  
  769.     if (ssnd_remaining[fd] != -1)
  770.     {
  771.     AIFFerrno = AIFF_PARAMSFIXED;
  772.     return -1;
  773.     }
  774.  
  775.     if (channels == 0)
  776.     channels = DEFAULT_CHANNELS;
  777.     audioparams[fd].nchannels = channels;
  778.  
  779.     return 0;
  780. }
  781.  
  782.  
  783. int AIFFsetwidth(AIFFfile fd, int width)
  784. {
  785.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  786.     {
  787.     AIFFerrno = AIFF_BADFD;
  788.     return -1;
  789.     }
  790.  
  791.     /*
  792.      *  make sure file is write and we haven't written any sound yet
  793.      */
  794.  
  795.     if (ssnd_remaining[fd] != -1)
  796.     {
  797.     AIFFerrno = AIFF_PARAMSFIXED;
  798.     return -1;
  799.     }
  800.  
  801.     if (width == 0)
  802.     width = DEFAULT_WIDTH;
  803.     audioparams[fd].sampwidth = width;
  804.  
  805.     return 0;
  806. }
  807.  
  808.  
  809. int AIFFsetrate(AIFFfile fd, int rate)
  810. {
  811.     if (fd < 0 || fd >= MAXFILES || !busy[fd])
  812.     {
  813.     AIFFerrno = AIFF_BADFD;
  814.     return -1;
  815.     }
  816.  
  817.     /*
  818.      *  make sure file is write and we haven't written any sound yet
  819.      */
  820.  
  821.     if (ssnd_remaining[fd] != -1)
  822.     {
  823.     AIFFerrno = AIFF_PARAMSFIXED;
  824.     return -1;
  825.     }
  826.  
  827.     if (rate == 0)
  828.     rate = DEFAULT_RATE;
  829.     audioparams[fd].samprate = rate;
  830.  
  831.     return 0;
  832. }
  833.  
  834.  
  835. static int widthtobytes(int width)
  836. {
  837.     switch (width)
  838.     {
  839.     case  8: return 1;
  840.     case 16: return 2;
  841.     case 24: return 4;        /* FIXME: is this 3 or 4 */
  842.     default: return -1;
  843.     }
  844. }
  845.  
  846.  
  847. int CONVERTchannelstoAL(int channels)
  848. {
  849.     switch (channels)
  850.     {
  851.     case 1: return AL_MONO;
  852.     case 2: return AL_STEREO;
  853.     default: AIFFerrno = AIFF_BADCHANNELS; return -1;
  854.     }
  855. }
  856.  
  857.  
  858. int CONVERTALtochannels(int ALchannels)
  859. {
  860.     switch (ALchannels)
  861.     {
  862.     case AL_MONO:   return 1;
  863.     case AL_STEREO: return 2;
  864.     default: AIFFerrno = AIFF_BADCHANNELS; return -1;
  865.     }
  866. }
  867.  
  868.  
  869. int CONVERTwidthtoAL(int width)
  870. {
  871.     switch (width)
  872.     {
  873.     case  8: return AL_SAMPLE_8;
  874.     case 16: return AL_SAMPLE_16;
  875.     case 24: return AL_SAMPLE_24;
  876.     default: AIFFerrno = AIFF_BADWIDTH; return -1;
  877.     }
  878. }
  879.  
  880.  
  881. int CONVERTALtowidth(int ALwidth)
  882. {
  883.     switch (ALwidth)
  884.     {
  885.     case AL_SAMPLE_8:  return 8;
  886.     case AL_SAMPLE_16: return 16;
  887.     case AL_SAMPLE_24: return 24;
  888.     default: AIFFerrno = AIFF_BADWIDTH; return -1;
  889.     }
  890. }
  891.  
  892.  
  893. int CONVERTratetoAL(int rate)
  894. {
  895.     switch (rate)
  896.     {
  897.     case 48000: return AL_RATE_48000;
  898.     case 44100: return AL_RATE_44100;
  899.     case 32000: return AL_RATE_32000;
  900.     case 22050: return AL_RATE_22050;
  901.     case 16000: return AL_RATE_16000;
  902.     case 11025: return AL_RATE_11025;
  903.     case  8000: return AL_RATE_8000;
  904.     default: AIFFerrno = AIFF_BADRATE; return -1;
  905.     }
  906. }
  907.  
  908.  
  909. int CONVERTALtorate(int ALrate)
  910. {
  911.     switch (ALrate)
  912.     {
  913.     case AL_RATE_48000: return 48000;
  914.     case AL_RATE_44100: return 44100;
  915.     case AL_RATE_32000: return 32000;
  916.     case AL_RATE_16000: return 16000;
  917.     case AL_RATE_8000:  return 8000;
  918.     default: AIFFerrno = AIFF_BADRATE; return -1;
  919.     }
  920. }
  921.  
  922.  
  923. void    AIFFerror(const char* s)
  924. {
  925.     if (s && *s)
  926.     fprintf(stderr,"%s: ",s);
  927.     fprintf(stderr,"%s\n",AIFFerrstr[-AIFFerrno]);
  928.     AIFFerrno = 0;
  929. }
  930.  
  931.  
  932. char*    AIFFstrerror(int err)
  933. {
  934.     return AIFFerrstr[-err];
  935. }
  936.  
  937.  
  938. /*
  939.  * Copyright (C) 1988-1991 Apple Computer, Inc.
  940.  * All rights reserved.
  941.  *
  942.  * Machine-independent I/O routines for IEEE floating-point numbers.
  943.  *
  944.  * NaN's and infinities are converted to HUGE_VAL or HUGE, which
  945.  * happens to be infinity on IEEE machines.  Unfortunately, it is
  946.  * impossible to preserve NaN's in a machine-independent way.
  947.  * Infinities are, however, preserved on IEEE machines.
  948.  *
  949.  * These routines have been tested on the following machines:
  950.  *    Apple Macintosh, MPW 3.1 C compiler
  951.  *    Apple Macintosh, THINK C compiler
  952.  *    Silicon Graphics IRIS, MIPS compiler
  953.  *    Cray X/MP and Y/MP
  954.  *    Digital Equipment VAX
  955.  *
  956.  *
  957.  * Implemented by Malcolm Slaney and Ken Turkowski.
  958.  *
  959.  * Malcolm Slaney contributions during 1988-1990 include big- and little-
  960.  * endian file I/O, conversion to and from Motorola's extended 80-bit
  961.  * floating-point format, and conversions to and from IEEE single-
  962.  * precision floating-point format.
  963.  *
  964.  * In 1991, Ken Turkowski implemented the conversions to and from
  965.  * IEEE double-precision format, added more precision to the extended
  966.  * conversions, and accommodated conversions involving +/- infinity,
  967.  * NaN's, and denormalized numbers.
  968.  */
  969. #ifndef HUGE_VAL
  970. #define HUGE_VAL HUGE
  971. #endif
  972.  
  973. #define UnsignedToFloat(u)    \
  974.      (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
  975. #define FloatToUnsigned(f)  \
  976.     ((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L + 1))
  977.  
  978.  
  979. /****************************************************************
  980.  * Extended precision IEEE floating-point conversion routines.
  981.  ****************************************************************/
  982.  
  983. static double    ConvertFromIeeeExtended(char *bytes)
  984. {
  985.     double    f;
  986.     long    expon;
  987.     unsigned long hiMant, loMant;
  988.  
  989.     expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
  990.     hiMant    =    ((unsigned long)(bytes[2] & 0xFF) << 24)
  991.         |    ((unsigned long)(bytes[3] & 0xFF) << 16)
  992.         |    ((unsigned long)(bytes[4] & 0xFF) << 8)
  993.         |    ((unsigned long)(bytes[5] & 0xFF));
  994.     loMant    =    ((unsigned long)(bytes[6] & 0xFF) << 24)
  995.         |    ((unsigned long)(bytes[7] & 0xFF) << 16)
  996.         |    ((unsigned long)(bytes[8] & 0xFF) << 8)
  997.         |    ((unsigned long)(bytes[9] & 0xFF));
  998.  
  999.     if (expon == 0 && hiMant == 0 && loMant == 0)
  1000.     {
  1001.     f = 0;
  1002.     }
  1003.     else
  1004.     {
  1005.     if (expon == 0x7FFF)    /* Infinity or NaN */
  1006.     {
  1007.         f = HUGE_VAL;
  1008.     }
  1009.     else
  1010.     {
  1011.         expon -= 16383;
  1012.         f  = ldexp(UnsignedToFloat(hiMant), expon-=31);
  1013.         f += ldexp(UnsignedToFloat(loMant), expon-=32);
  1014.     }
  1015.     }
  1016.  
  1017.     if (bytes[0] & 0x80)
  1018.     return -f;
  1019.     else
  1020.     return f;
  1021. }
  1022.  
  1023.  
  1024. static void ConvertToIeeeExtended(double num, char *bytes)
  1025. {
  1026.     int sign;
  1027.     int expon;
  1028.     double fMant, fsMant;
  1029.     unsigned long hiMant, loMant;
  1030.  
  1031.     if (num < 0)
  1032.     {
  1033.     sign = 0x8000;
  1034.     num *= -1;
  1035.     }
  1036.     else
  1037.     {
  1038.     sign = 0;
  1039.     }
  1040.  
  1041.     if (num == 0)
  1042.     {
  1043.     expon = 0; hiMant = 0; loMant = 0;
  1044.     }
  1045.     else
  1046.     {
  1047.     fMant = frexp(num, &expon);
  1048.     if ((expon > 16384) || !(fMant < 1))    /* Infinity or NaN */
  1049.     {
  1050.         expon = sign|0x7FFF;        /* infinity */
  1051.         hiMant = 0;
  1052.         loMant = 0;
  1053.     }
  1054.     else    /* Finite */
  1055.     {
  1056.         expon += 16382;
  1057.         if (expon < 0)    /* denormalized */
  1058.         {
  1059.         fMant = ldexp(fMant, expon);
  1060.         expon = 0;
  1061.         }
  1062.         expon |= sign;
  1063.         fMant = ldexp(fMant, 32);
  1064.         fsMant = floor(fMant);
  1065.         hiMant = FloatToUnsigned(fsMant);
  1066.         fMant = ldexp(fMant - fsMant, 32);
  1067.         fsMant = floor(fMant);
  1068.         loMant = FloatToUnsigned(fsMant);
  1069.     }
  1070.     }
  1071.  
  1072.     bytes[0] = expon >> 8;
  1073.     bytes[1] = expon;
  1074.     bytes[2] = hiMant >> 24;
  1075.     bytes[3] = hiMant >> 16;
  1076.     bytes[4] = hiMant >> 8;
  1077.     bytes[5] = hiMant;
  1078.     bytes[6] = loMant >> 24;
  1079.     bytes[7] = loMant >> 16;
  1080.     bytes[8] = loMant >> 8;
  1081.     bytes[9] = loMant;
  1082. }
  1083.  
  1084.